﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using WeifenLuo.WinFormsUI.Docking;
using System.Xml;
using System.Collections;
using System.Reflection;
using System.Threading;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using ICSharpCode.SharpZipLib.Zip;
using System.Net;

namespace ApqUpdater
{
	public partial class MainForm : Apq.Windows.Forms.ImeForm
	{
		public MainForm()
		{
			InitializeComponent();
		}

		private Apq.Net.RFileInfo _RFileInfo = new Apq.Net.RFileInfo();
		// 进度锁
		private object _lockJinDu = new object();
		// 每个文件的分块数
		private const int Num_Section = 5;
		// 解压线程
		private Thread _tUnzip = null;

		private string _tmpDownFolder = string.Empty;

		// 当前升级号
		private int _CurNo = 0;
		// 服务器上最后的升级号,升级完成后,本地升级号即为此号
		private int _LastNo = 0;
		// 已解压文件数
		private int _FileNum = 0;
		// 解压目标路径,从AppEnter中获取,为空则表示为升级程序所在目录,当升级程序和主程序位于同一路径时可只填主程序exe文件名
		private string _strPath = string.Empty;

		private Regex _regFileName = new Regex(@"\[(\d+)\].*");

		private void MainForm_Load(object sender, EventArgs e)
		{
			#region 读取标题
			string cfgText = GlobalObject.XmlAsmConfig[this.GetType(), "ProgTitle"];
			if (cfgText != null)
			{
				Text = cfgText;
			}
			#endregion

			lblInfo.Text = string.Empty;
			_tmpDownFolder = Path.GetDirectoryName(Apq.GlobalObject.TheProcess.MainModule.FileName) + "\\Down";
			_CurNo = Apq.Convert.ChangeType<int>(GlobalObject.XmlAsmConfig[this.GetType(), "LastNo"]);
			_strPath = Path.GetDirectoryName(GlobalObject.XmlAsmConfig[this.GetType(), "AppEnter"]);
			if (string.IsNullOrWhiteSpace(_strPath))
			{
				_strPath = Path.GetDirectoryName(Apq.GlobalObject.TheProcess.MainModule.FileName);
			}

			_RFileInfo.AddDownColumn();

			// 使用Ftp
			//MainBackThread = Apq.Threading.Thread.StartNewThread(new ThreadStart(FtpDoUpdate));
			// 使用Http(单块)
			//MainBackThread = Apq.Threading.Thread.StartNewThread(new ThreadStart(HttpDoUpdate1));
			// 使用Http(分块)
			MainBackThread = Apq.Threading.Thread.StartNewThread(new ThreadStart(HttpDoUpdate));
		}

		#region Ftp下载
		/// <summary>
		/// 执行升级
		/// </summary>
		private void FtpDoUpdate()
		{
			try
			{
				FtpGetFileList();
			}
			catch (Exception ex)
			{
				Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
				{
					lblInfo.Text = "无法连接升级服务器,跳过升级";

					btnStart.Enabled = true;
				});
				Apq.GlobalObject.ApqLog.Error("无法连接升级服务器", ex);
			}

			if (_RFileInfo.RFile.Count < 1)
			{
				btnStart_Click(null, null);
				return;
			}

			// 设置将要解压的文件数为即将下载的文件数
			Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
			{
				pbUnzip.Maximum = _RFileInfo.RFile.Count;
				lblInfo.Text = string.Format("找到 {0} 个升级包,正在更新...", pbUnzip.Maximum);
			});

			// 启动下载控制线程,去执行文件分块下载
			ManualResetEvent[] manuls = new ManualResetEvent[_RFileInfo.RFile.Count];
			for (int i = 0; i < _RFileInfo.RFile.Count; i++)
			{
				Apq.Net.RFileInfo.RFileRow dr = (Apq.Net.RFileInfo.RFileRow)_RFileInfo.RFile.Rows[i];
				string strFullFileName = _tmpDownFolder + "\\" + dr.FileName;

				ParameterizedThreadStart pts = new ParameterizedThreadStart(FtpDownFileControler);
				Apq.Threading.EventThreadArgs args = new Apq.Threading.EventThreadArgs();
				dr["ManualResetEvent"] = args.ManualResetEvent = manuls[i] = new ManualResetEvent(false);
				args.Param = dr;
				args.ManualResetEvent.Reset();

				dr["LocalFile"] = strFullFileName;
				Thread t = Apq.Threading.Thread.StartNewThread(pts, args);
				dr["ThreadC"] = t;
			}

			// 启动解压线程
			WaitHandle.WaitAll(manuls);
			_tUnzip = Apq.Threading.Thread.StartNewThread(UnzipWorker);
		}

		/// <summary>
		/// 获取待下载的文件列表
		/// </summary>
		public void FtpGetFileList()
		{
			int LastNo = _CurNo;

			Apq.Net.FtpClient fc = CreateFtpClientFromCfg();
			List<string> _lstFile = fc.GetFileList(string.Empty);

			foreach (string str in _lstFile)
			{
				MatchCollection mc = _regFileName.Matches(str);
				if (mc.Count > 0)
				{
					int FileNo = Apq.Convert.ChangeType<int>(mc[0].Groups[1].Value);

					// 将服务器上最大的升级号记录下来
					if (_LastNo < FileNo)
					{
						_LastNo = FileNo;
					}

					// 只下载比本地升级号大的文件
					if (FileNo > _CurNo)
					{
						long nFileSize = fc.GetFileSize(str);
						_RFileInfo.RFile.AddRFileRow(str, Path.GetFileName(str), nFileSize);
					}
				}
			}
		}

		/// <summary>
		/// 下载控制线程
		/// </summary>
		/// <param name="objFileStr"></param>
		public void FtpDownFileControler(object obj)
		{
			Apq.Threading.EventThreadArgs args = obj as Apq.Threading.EventThreadArgs;

			if (args != null)
			{
				Apq.Net.RFileInfo.RFileRow dr = Apq.Convert.ChangeType<Apq.Net.RFileInfo.RFileRow>(args.Param);

				//文件分块
				List<Apq.IO.FileSection> lstFSec = Apq.IO.FileSection.CalcSection(dr.Size, Num_Section, dr.Url);
				string strLocalFile = Apq.Convert.ChangeType<string>(dr["LocalFile"]);
				Apq.IO.FileCache Cache = new Apq.IO.FileCache(strLocalFile, lstFSec);

				// 加入分块表并启动下载线程
				ManualResetEvent[] manuls = new ManualResetEvent[Cache.FileSecCaches.Count];
				for (int i = 0; i < Cache.FileSecCaches.Count; i++)
				{
					Apq.Net.RFileInfo.RFileSectionRow drSec = _RFileInfo.RFileSection.AddRFileSectionRow(dr.Url, dr.FileName, dr.Size);
					drSec["LocalFile"] = dr["LocalFile"];
					drSec["FileCache"] = Cache;
					drSec["SecNo"] = lstFSec[i].SubNo;

					ParameterizedThreadStart pts = new ParameterizedThreadStart(FtpDownFileWorker);
					Apq.Threading.EventThreadArgs argsD = new Apq.Threading.EventThreadArgs();
					argsD.ManualResetEvent = manuls[i] = new ManualResetEvent(false);
					argsD.Param = drSec;
					argsD.ManualResetEvent.Reset();

					Thread t = Apq.Threading.Thread.StartNewThread(pts, argsD);
					drSec["ThreadD"] = t;
				}

				// 该文件下载完成,通知控制线程
				WaitHandle.WaitAll(manuls);
				Cache.Flush();
				Cache.FS.Close();
				args.ManualResetEvent.Set();
			}
		}

		/// <summary>
		/// 下载文件,完成后启动解压(替换文件)线程
		/// </summary>
		/// <param name="objFileStr"></param>
		public void FtpDownFileWorker(object obj)
		{
			Apq.Threading.EventThreadArgs args = obj as Apq.Threading.EventThreadArgs;

			if (args != null)
			{
				Apq.Net.RFileInfo.RFileSectionRow drSec = Apq.Convert.ChangeType<Apq.Net.RFileInfo.RFileSectionRow>(args.Param);

				Apq.Net.FtpClient fc = CreateFtpClientFromCfg();
				fc.ObjectName = drSec.Url;
				fc.JinDuChanged += new Apq.JinDu.JinDuChangedHandler(x_JinDuChanged);

				string strFullFileName = Apq.Convert.ChangeType<string>(drSec["LocalFile"]);
				Apq.IO.FileCache Cache = Apq.Convert.ChangeType<Apq.IO.FileCache>(drSec["FileCache"]);
				int SecNo = Apq.Convert.ChangeType<int>(drSec["SecNo"]);

				fc.DownFileSection(strFullFileName, Cache, SecNo);

				// 本块下载完成以后:
				args.ManualResetEvent.Set();
			}
		}
		#endregion

		#region Http下载(分块)
		/// <summary>
		/// 执行升级
		/// </summary>
		private void HttpDoUpdate()
		{
			try
			{
				HttpGetFileList();
			}
			catch (Exception ex)
			{
				Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
				{
					lblInfo.Text = "无法连接升级服务器,跳过升级";

					btnStart.Enabled = true;
				});
				Apq.GlobalObject.ApqLog.Error("无法连接升级服务器", ex);
			}

			if (_RFileInfo.RFile.Count < 1)
			{
				btnStart_Click(null, null);
				return;
			}

			// 设置将要解压的文件数为即将下载的文件数
			Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
			{
				pbUnzip.Maximum = _RFileInfo.RFile.Count;
				lblInfo.Text = string.Format("找到 {0} 个升级包,正在更新...", pbUnzip.Maximum);
			});

			// 启动下载控制线程,去执行文件分块下载
			ManualResetEvent[] manuls = new ManualResetEvent[_RFileInfo.RFile.Count];
			for (int i = 0; i < _RFileInfo.RFile.Count; i++)
			{
				Apq.Net.RFileInfo.RFileRow dr = (Apq.Net.RFileInfo.RFileRow)_RFileInfo.RFile.Rows[i];
				string strFullFileName = _tmpDownFolder + "\\" + dr.FileName;

				ParameterizedThreadStart pts = new ParameterizedThreadStart(HttpDownFileControler);
				Apq.Threading.EventThreadArgs args = new Apq.Threading.EventThreadArgs();
				dr["ManualResetEvent"] = args.ManualResetEvent = manuls[i] = new ManualResetEvent(false);
				args.Param = dr;
				args.ManualResetEvent.Reset();

				dr["LocalFile"] = strFullFileName;
				Thread t = Apq.Threading.Thread.StartNewThread(pts, args);
				dr["ThreadC"] = t;
			}

			// 启动解压线程
			WaitHandle.WaitAll(manuls);
			_tUnzip = Apq.Threading.Thread.StartNewThread(UnzipWorker);
		}

		/// <summary>
		/// 获取待下载的文件列表
		/// </summary>
		public void HttpGetFileList()
		{
			int LastNo = _CurNo;

			try
			{
				XmlDocument xdFileList = new XmlDocument();
				xdFileList.Load(GlobalObject.XmlAsmConfig[this.GetType(), "FileList"]);

				XmlNodeList xnl = xdFileList.SelectNodes("/Root/File");
				foreach (XmlElement xe in xnl)
				{
					string strUrl = xe.InnerText;
					int FileNo = Apq.Convert.ChangeType<int>(xe.Attributes["No"].Value);

					// 将服务器上最大的升级号记录下来
					if (_LastNo < FileNo)
					{
						_LastNo = FileNo;
					}

					// 只下载比本地升级号大的文件
					if (FileNo > _CurNo)
					{
						Apq.Net.HttpWebRequest reqHttp = new Apq.Net.HttpWebRequest();
						long nFileSize = reqHttp.GetFileSize(strUrl);
						_RFileInfo.RFile.AddRFileRow(strUrl, Path.GetFileName(strUrl), nFileSize);
					}
				}
			}
			catch (Exception ex)
			{
				Apq.GlobalObject.ApqLog.Error("从Http获取文件列表出错", ex);
			}
		}

		/// <summary>
		/// 下载控制线程
		/// </summary>
		/// <param name="objFileStr"></param>
		public void HttpDownFileControler(object obj)
		{
			Apq.Threading.EventThreadArgs args = obj as Apq.Threading.EventThreadArgs;

			if (args != null)
			{
				Apq.Net.RFileInfo.RFileRow dr = Apq.Convert.ChangeType<Apq.Net.RFileInfo.RFileRow>(args.Param);

				//文件分块
				List<Apq.IO.FileSection> lstFSec = Apq.IO.FileSection.CalcSection(dr.Size, Num_Section, dr.Url);
				string strLocalFile = Apq.Convert.ChangeType<string>(dr["LocalFile"]);
				Apq.IO.FileCache Cache = new Apq.IO.FileCache(strLocalFile, lstFSec);

				// 加入分块表并启动下载线程
				ManualResetEvent[] manuls = new ManualResetEvent[Cache.FileSecCaches.Count];
				for (int i = 0; i < Cache.FileSecCaches.Count; i++)
				{
					Apq.Net.RFileInfo.RFileSectionRow drSec = _RFileInfo.RFileSection.AddRFileSectionRow(dr.Url, dr.FileName, dr.Size);
					drSec["LocalFile"] = dr["LocalFile"];
					drSec["FileCache"] = Cache;
					drSec["SecNo"] = lstFSec[i].SubNo;

					ParameterizedThreadStart pts = new ParameterizedThreadStart(HttpDownFileWorker);
					Apq.Threading.EventThreadArgs argsD = new Apq.Threading.EventThreadArgs();
					argsD.ManualResetEvent = manuls[i] = new ManualResetEvent(false);
					argsD.Param = drSec;
					argsD.ManualResetEvent.Reset();

					Thread t = Apq.Threading.Thread.StartNewThread(pts, argsD);
					drSec["ThreadD"] = t;
				}

				// 该文件下载完成,通知控制线程
				WaitHandle.WaitAll(manuls);
				Cache.Flush();
				Cache.FS.Close();
				args.ManualResetEvent.Set();
			}
		}

		/// <summary>
		/// 下载文件,完成后启动解压(替换文件)线程
		/// </summary>
		/// <param name="objFileStr"></param>
		public void HttpDownFileWorker(object obj)
		{
			Apq.Threading.EventThreadArgs args = obj as Apq.Threading.EventThreadArgs;

			if (args != null)
			{
				Apq.Net.RFileInfo.RFileSectionRow drSec = Apq.Convert.ChangeType<Apq.Net.RFileInfo.RFileSectionRow>(args.Param);

				Apq.Net.HttpWebRequest reqHttp = new Apq.Net.HttpWebRequest();
				reqHttp.JinDuChanged += new Apq.JinDu.JinDuChangedHandler(x_JinDuChanged);

				string strFullFileName = Apq.Convert.ChangeType<string>(drSec["LocalFile"]);
				Apq.IO.FileCache Cache = Apq.Convert.ChangeType<Apq.IO.FileCache>(drSec["FileCache"]);
				int SecNo = Apq.Convert.ChangeType<int>(drSec["SecNo"]);

				reqHttp.DownFileSection(strFullFileName, Cache, SecNo);

				// 本块下载完成以后:
				args.ManualResetEvent.Set();
			}
		}
		#endregion

		#region Http下载(未分块)
		/// <summary>
		/// 执行升级
		/// </summary>
		private void HttpDoUpdate1()
		{
			try
			{
				HttpGetFileList();
			}
			catch (Exception ex)
			{
				Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
				{
					lblInfo.Text = "无法连接升级服务器,跳过升级";

					btnStart.Enabled = true;
				});
				Apq.GlobalObject.ApqLog.Error("无法连接升级服务器", ex);
			}

			if (_RFileInfo.RFile.Count < 1)
			{
				btnStart_Click(null, null);
				return;
			}

			// 设置将要解压的文件数为即将下载的文件数
			Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
			{
				pbUnzip.Maximum = _RFileInfo.RFile.Count;
				lblInfo.Text = string.Format("找到 {0} 个升级包,正在更新...", pbUnzip.Maximum);
			});

			// 启动下载线程
			ManualResetEvent[] manuls = new ManualResetEvent[_RFileInfo.RFile.Count];
			for (int i = 0; i < _RFileInfo.RFile.Count; i++)
			{
				Apq.Net.RFileInfo.RFileRow dr = (Apq.Net.RFileInfo.RFileRow)_RFileInfo.RFile.Rows[i];
				dr["LocalFile"] = _tmpDownFolder + "\\" + dr.FileName;

				ParameterizedThreadStart pts = new ParameterizedThreadStart(HttpDownFileWorker1);
				Apq.Threading.EventThreadArgs args = new Apq.Threading.EventThreadArgs();
				args.ManualResetEvent = manuls[i] = new ManualResetEvent(false);
				args.Param = dr;
				args.ManualResetEvent.Reset();

				Thread t = Apq.Threading.Thread.StartNewThread(pts, args);
				dr["ThreadC"] = t;
			}

			// 启动解压线程
			WaitHandle.WaitAll(manuls);
			_tUnzip = Apq.Threading.Thread.StartNewThread(UnzipWorker);
		}

		/// <summary>
		/// 下载文件,完成后启动解压(替换文件)线程
		/// </summary>
		/// <param name="objFileStr"></param>
		public void HttpDownFileWorker1(object obj)
		{
			Apq.Threading.EventThreadArgs args = obj as Apq.Threading.EventThreadArgs;

			if (args != null)
			{
				Apq.Net.RFileInfo.RFileRow dr = Apq.Convert.ChangeType<Apq.Net.RFileInfo.RFileRow>(args.Param);
				Apq.Net.HttpWebRequest reqHttp = new Apq.Net.HttpWebRequest();
				reqHttp.JinDuChanged += new Apq.JinDu.JinDuChangedHandler(reqHttp_JinDuChanged1);

				string strFullFileName = _tmpDownFolder + "\\" + Path.GetFileName(dr.Url);

				// 不支持分块,所以只分一块
				List<Apq.IO.FileSection> lstFSec = Apq.IO.FileSection.CalcSection(dr.Size, 1, dr.Url);
				lstFSec[0].ManualResetEvent = args.ManualResetEvent;
				reqHttp.DownFile(strFullFileName, lstFSec[0]);
			}
		}

		void reqHttp_JinDuChanged1(object sender, Apq.JinDu.JinDu e)
		{
			lock (_lockJinDu)
			{
				Apq.Net.RFileInfo.RFileRow dr = _RFileInfo.RFile.Find(e.Name);
				dr["JinDu"] = e;

				// 将下载进度显示到界面(用所有文件的总量和已下载量进行设置)
				Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
				{
					// 计算总量和已下载量
					long nTotal = 0;
					long nCureent = 0;
					foreach (Apq.Net.RFileInfo.RFileRow tmp in _RFileInfo.RFile.Rows)
					{
						nTotal += tmp.Size;
						Apq.JinDu.JinDu j = Apq.Convert.ChangeType<Apq.JinDu.JinDu>(tmp["JinDu"]);
						if (j != null) nCureent += j.Current;
					}

					// 本次进度比上次大才显示到界面
					if (nCureent > pbDown.Value)
					{
						// 设置下载进度
						if (nTotal > int.MaxValue || nCureent > int.MaxValue)
						{
							nTotal >>= 32;
							nCureent >>= 32;
						}

						pbDown.Maximum = (int)nTotal;
						pbDown.Value = (int)nCureent;
					}

					//Apq.GlobalObject.ApqLog.Info(string.Format("[HTTP]总量: {0} 已下载量{1}", pbDown.Maximum, pbDown.Value));
				});
			}
		}
		#endregion

		/// <summary>
		/// 解压文件,替换方式
		/// </summary>
		/// <param name="objFileStr"></param>
		public void UnzipWorker()
		{
			string strDirTarget = Path.GetDirectoryName(Apq.GlobalObject.TheProcess.MainModule.FileName);

			foreach (Apq.Net.RFileInfo.RFileRow dr in _RFileInfo.RFile.Rows)
			{
				string strFile = Apq.Convert.ChangeType<string>(dr["LocalFile"]);

				try
				{
					FastZip fz = new FastZip();
					// 以覆盖方式解压
					fz.ExtractZip(strFile, _strPath, FastZip.Overwrite.Always, null, string.Empty, string.Empty, true);

					// 解压成功后文件数+1
					_FileNum++;

					// 记录已升级的文件名
					Apq.GlobalObject.ApqLog.Info(string.Format("已成功升级的文件:{0}", strFile));
				}
				catch (Exception ex)
				{
					Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
					{
						lblInfo.Text = "解压时出错,更新失败!";
					});

					Apq.GlobalObject.ApqLog.Error("解压失败", ex);
				}
				finally
				{
					Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
					{
						pbUnzip.PerformStep();

						// 如果更新完成,则启用"启动"按钮
						if (_FileNum >= _RFileInfo.RFile.Count)
						{
							// 更新本地版本号
							_CurNo = _LastNo;
							GlobalObject.XmlAsmConfig[this.GetType(), "LastNo"] = _CurNo.ToString();

							btnStart.Enabled = true;

							lblInfo.Text = "升级成功!";

							if (Apq.Convert.ChangeType<bool>(GlobalObject.XmlAsmConfig[this.GetType(), "AutoEnter"]))
							{
								btnStart_Click(null, null);
							}
						}
					});
				}
			}
		}

		void x_JinDuChanged(object sender, Apq.JinDu.JinDu e)
		{
			lock (_lockJinDu)
			{
				Apq.Net.RFileInfo.RFileSectionRow drSec = _RFileInfo.RFileSection.Find(e.Name, e.SubNo);
				drSec["JinDu"] = e;

				// 将下载进度显示到界面(用所有文件的总量和已下载量进行设置)
				Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
				{
					// 计算总量
					long nTotal = 0;
					foreach (Apq.Net.RFileInfo.RFileRow tmp in _RFileInfo.RFile.Rows)
					{
						nTotal += tmp.Size;
					}
					// 计算已下载量
					long nCureent = 0;
					foreach (Apq.Net.RFileInfo.RFileSectionRow tmp in _RFileInfo.RFileSection.Rows)
					{
						Apq.JinDu.JinDu j = Apq.Convert.ChangeType<Apq.JinDu.JinDu>(tmp["JinDu"]);
						if (j != null) nCureent += j.Current;
					}

					// 本次进度比上次大才显示到界面
					if (nCureent > pbDown.Value)
					{
						// 设置下载进度
						if (nTotal > int.MaxValue || nCureent > int.MaxValue)
						{
							nTotal >>= 32;
							nCureent >>= 32;
						}

						pbDown.Maximum = (int)nTotal;
						pbDown.Value = (int)nCureent;
					}

					//Apq.GlobalObject.ApqLog.Info(string.Format("[FTP]总量: {0} 已下载量{1}",pbDown.Maximum,pbDown.Value));
				});
			}
		}

		/// <summary>
		/// 从配置文件创建FtpClient
		/// </summary>
		/// <returns></returns>
		private Apq.Net.FtpClient CreateFtpClientFromCfg()
		{
			string FtpServer = GlobalObject.XmlAsmConfig[this.GetType(), "FtpServer"];
			int FtpPort = Apq.Convert.ChangeType<int>(GlobalObject.XmlAsmConfig[this.GetType(), "FtpPort"], 21);
			string FtpPath = GlobalObject.XmlAsmConfig[this.GetType(), "FtpPath"];
			Apq.Net.FtpClient fc = new Apq.Net.FtpClient(FtpServer, FtpPort, FtpPath, string.Empty, string.Empty);
			return fc;
		}

		private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
		{
			// 保存配置文件
			GlobalObject.XmlConfigChain.Save();
		}

		private void btnSkip_Click(object sender, EventArgs e)
		{
			AbortAll();
			btnStart.Enabled = true;
			btnStart_Click(sender, e);
		}

		private void btnStart_Click(object sender, EventArgs e)
		{
			Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
			{
				try
				{
					Process.Start(GlobalObject.XmlAsmConfig[this.GetType(), "AppEnter"]);
					Close();
				}
				catch (Exception ex)
				{
					MessageBox.Show("启动程序失败!");
					Apq.GlobalObject.ApqLog.Error("启动程序失败", ex);
				}
			});
		}

		private void btnRetry_Click(object sender, EventArgs e)
		{
			AbortAll();

			MainBackThread = Apq.Threading.Thread.StartNewThread(new ThreadStart(FtpDoUpdate));
		}

		/// <summary>
		/// 中止所有升级过程,并将进度归0
		/// </summary>
		private void AbortAll()
		{
			Apq.Threading.Thread.Abort(MainBackThread);
			foreach (Apq.Net.RFileInfo.RFileRow drFile in _RFileInfo.RFile.Rows)
			{
				Thread t = Apq.Convert.ChangeType<Thread>(drFile["ThreadC"]);
				Apq.Threading.Thread.Abort(t);
			}
			foreach (Apq.Net.RFileInfo.RFileSectionRow drSec in _RFileInfo.RFile.Rows)
			{
				Thread t = Apq.Convert.ChangeType<Thread>(drSec["ThreadD"]);
				Apq.Threading.Thread.Abort(t);
			}
			Apq.Threading.Thread.Abort(_tUnzip);

			_RFileInfo.Clear();
			_FileNum = 0;

			// 进度条归0
			Apq.Windows.Delegates.Action_UI<Label>(lblInfo, lblInfo, delegate(Label lbl)
			{
				pbDown.Value = 0;
				pbUnzip.Value = 0;
			});
		}
	}
}